// 那如果生产者在一直生产，消费者不可以用信号量堵塞生产者，只能不断接受生产者的输出，可以接受的比生产慢，但是不能信号丢失，这种情况如何解决
#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>

#define BUFFER_SIZE 5 // 缓冲区大小

int buffer[BUFFER_SIZE]; // 缓冲区
int in = 0; // 写入位置
int out = 0; // 读取位置

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // 互斥锁
sem_t empty_slots; // 空槽信号量
sem_t filled_slots; // 数据信号量

void* producer(void* arg) {
    for (int i = 0; i < 10; i++) { // 假设生产10个数据
        //如果 empty_slots 的值大于 0，表示有空槽，生产者可以继续生产数据，并将 empty_slots 的值减 1。
        // 如果 empty_slots 的值为 0，生产者会阻塞，直到消费者释放空槽。
        sem_wait(&empty_slots); // 等待空槽
        
        pthread_mutex_lock(&mutex); // 加锁保护缓冲区

        // 生产数据
        buffer[in] = i;
        printf("Produced: %d\n", buffer[in]);
        in = (in + 1) % BUFFER_SIZE; // 循环缓冲区

        pthread_mutex_unlock(&mutex); // 解锁
        sem_post(&filled_slots); // 增加已填充槽的信号量,sem_post() 函数会将 filled_slots 的值加 1，表示有新的数据可供消费者消费。
    }
    return NULL;
}

void* consumer(void* arg) {
    for (int i = 0; i < 10; i++) { // 假设消费10个数据
        sem_wait(&filled_slots); // 等待数据槽
        pthread_mutex_lock(&mutex); // 加锁保护缓冲区

        // 消费数据
        int item = buffer[out];
        printf("Consumed: %d\n", item);
        out = (out + 1) % BUFFER_SIZE; // 循环缓冲区

        pthread_mutex_unlock(&mutex); // 解锁
        sem_post(&empty_slots); // 增加空槽的信号量
    }
    return NULL;
}

int main() {
    pthread_t tid1, tid2;

    // 初始化信号量
    sem_init(&empty_slots, 0, BUFFER_SIZE); // 初始空槽数量为缓冲区大小，如果为 0，表示信号量用于线程间同步（即信号量在线程间共享）。
    // 如果为非零值，表示信号量用于进程间同步（需要放在共享内存中）。
    sem_init(&filled_slots, 0, 0); // 初始已填充槽数量为0

    // 创建生产者和消费者线程
    pthread_create(&tid2, NULL, consumer, NULL);
    pthread_create(&tid1, NULL, producer, NULL);
    

    // 等待线程结束
    pthread_join(tid2, NULL);
    pthread_join(tid1, NULL);
    

    // 销毁信号量和互斥锁
    sem_destroy(&empty_slots);
    sem_destroy(&filled_slots);
    pthread_mutex_destroy(&mutex);

    return 0;
}